Release 10.1A: OpenEdge Deployment:
Managing 4GL Applications


RCODE–INFO handle

The RCODE-INFO system handle lets you read the r-code CRC from an r-code file. You can use this value to:

Getting the r-code CRC

To read the r-code CRC from an r-code file, first set the FILE-NAME attribute of the RCODE-INFO handle to the pathname of your r-code file. Then read the value of the CRC-VALUE attribute:

DEFINE VARIABLE rCRC AS INTEGER.
RCODE-INFO:FILE-NAME = "sports/crcust.r".
rCRC = RCODE-INFO:CRC-VALUE. 

Note: The RCODE-INFO handle cannot read the r-code CRC from a session compile. For source (.p) procedures, the CRC-VALUE attribute returns the Unknown value (?).

Example — Verifying application r-code integrity

Be sure to verify the integrity of your application’s r-code.

To provide r-code integrity and security in your application:

  1. Build the procedure security table, RcodeSecurity, with these fields:
    • FilenameCHARACTER field for the pathname of each r-code file.
    • CRCINTEGER field for the r-code CRC of the specified r-code file.
  2. Construct a text file, crctable.dat, that contains a list of the relative pathnames for all the secure procedures called by your application.
  3. Compile and save the r-code for all the secure procedures in your application.
  4. Run a procedure that contains code like this to build the RcodeSecurity table:
  5. DEFINE VARIABLE i AS INTEGER.
    DEFINE VARIABLE proc-name AS CHARACTER FORMAT "x(32)".
    DEFINE VARIABLE rCRC AS INTEGER.
    
    INPUT FROM "crctable.dat". /* List of r-code file pathnames */
    
    i = 0.
    REPEAT:
        SET proc-name.
        FIND RcodeSecurity WHERE Filename = proc-name NO-ERROR.
        IF NOT AVAILABLE(RcodeSecurity) THEN
            CREATE RcodeSecurity.
        RCODE-INFO:FILE-NAME = proc-name.
        SET RcodeSecurity.Filename = proc-name
            RcodeSecurity.Crc = RCODE-INFO:CRC-VALUE.
        i = i + 1.
    END.
    
    INPUT CLOSE.
    MESSAGE i "procedure security records created". 
    

  6. At each point where you call a secure procedure in your application, insert this code:
  7. FIND RcodeSecurity WHERE Filename = "secret.r".
    RCODE-INFO:FILE-NAME = "secret.r".
    
    IF RcodeSecurity.Crc = RCODE-INFO:CRC-VALUE THEN
        RUN secret.
    ELSE DO:
        MESSAGE "Procedure secret.r is invalid.".
        QUIT.
    END. 
    

Example — Deploying schema triggers

The following procedure installs new schema trigger definitions in an existing database. It reads dump files that contain the new data for table and field metaschema trigger records and updates these records with the new trigger procedure names and CRCs:

trload.p
/* trload.p */
DEFINE VARIABLE i AS INTEGER.
DEFINE VARIABLE event AS CHARACTER FORMAT "x(6)".
DEFINE VARIABLE proc-name AS CHARACTER FORMAT "x(32)".
DEFINE VARIABLE table-name AS CHARACTER FORMAT "x(32)".
DEFINE VARIABLE field-name AS CHARACTER FORMAT "x(32)".
DEFINE VARIABLE rCRC AS INTEGER.
INPUT FROM "_file-tr.dat". /* Table trigger data */
i = 0.
_fl-loop:
REPEAT:
  SET table-name event proc-name.
  RCODE-INFO:FILE-NAME = proc-name.
  rCRC = RCODE-INFO:CRC-VALUE.
  FIND _file WHERE _file-name = table-name.
  FIND _file-trig WHERE _file-recid = RECID(_file) AND
                        _event = event NO-ERROR.
  IF AVAILABLE _file-trig THEN DO:    
    IF  _File-trig._Proc-name = proc-name
    AND _File-trig._Trig-CRC  = rCRC THEN 
        NEXT _fl-loop.
    ELSE DO:
    /* Progress doesn’t let you modify a trigger record, so delete and
       recreate. */
      DELETE _File-trig.
      CREATE _File-trig.
      ASSIGN _File-trig._File-recid = RECID(_File)
             _File-trig._Event      = event
             _File-trig._Override = TRUE
             _File-trig._Proc-Name  = proc-Name
             _File-trig._Trig-CRC   = rCRC
             i = i + 1. 
    END.
  END.
END. 
INPUT CLOSE.
MESSAGE i "_file-trig records updated.".
INPUT FROM "_field-t.dat". /* Field trigger data */
i = 0.
_fld-loop:
REPEAT:
  SET table-name field-name event proc-name.
  RCODE-INFO:FILE-NAME = proc-name.
  rCRC = RCODE-INFO:CRC-VALUE.
  FIND _file WHERE _file-name = table-name.
  FIND _field WHERE _file-recid = RECID(_file) AND 
                    _field-name = field-name.
  FIND _field-trig WHERE _field-trig._file-recid = RECID(_file) AND
                         _field-trig._field-recid = RECID(_field) AND
                         _event = event NO-ERROR.
  IF AVAILABLE _Field-trig      
      AND _Field-trig._Proc-name = proc-name 
      AND _Field-trig._Trig-CRC  = rCRC THEN NEXT _fld-loop.
  ELSE DO:
    DELETE _Field-trig.
CREATE _Field-trig.
    ASSIGN
      _Field-trig._File-recid  = RECID(_File)
      _Field-trig._Field-recid = RECID(_Field)
      _Field-trig._Event       = event
      _Field-trig._Override    = TRUE
      _Field-trig._Proc-Name   = proc-Name
      _Field-trig._Trig-CRC    = rCRC
      i = i + 1.
  END.  
END.
INPUT CLOSE.
MESSAGE i "_field-trig records updated.". 

Note: As this example shows, you must use the RECID function rather than the ROWID function to reference metaschema table record locations.

Example — Determining which files are affected by a database change

The following procedure demonstrates how you can use the RCODE-INFO system handle with the TABLE-LIST and TABLE-CRC-LIST attributes to help determine which files you need to recompile based upon a database change. TABLE-LIST generates a list of all the database tables that are referenced in the procedure file. TABLE-CRC-LIST generates a list of the corresponding table CRC values stored in the compiled procedure file. This example procedure then compares the CRC values in the procedure file with those stored in the database. If any of the values differ, you get a message stating that the procedure needs to be recompiled, as shown:

DEFINE VARIABLE tbllst AS CHARACTER. 
DEFINE VARIABLE crclst AS CHARACTER. 
DEFINE VARAIBLE hBuff AS HANDLE. 
DEFINE VARIABLE i AS INT. 
RCODE-INFO:FILE-NAME = "main.r". 
tbllst = RCODE-INFO:TABLE-LIST.  
crclst = RCODE-INFO:TABLE-CRC-LIST. 
REPEAT i = 1 TO NUM-ENTRIES(tbllst): 
   CREATE BUFFER hBuff FOR TABLE ENTRY(i, tbllst). 
   IF hBuff:CRC-VALUE = INTEGER(ENTRY(i, crclst)) 
      THEN MESSAGE “main.r does not need to be recompiled”. 
   ELSE MESSAGE “main.r needs to be recompiled”. 
   DELETE OBJECT hBuff. 
END. 

This procedure does not generate any warnings or error messages. If the r-code file was not compiled with any tables then the attribute returns the empty string. If the file is not found or is corrupted, the attribute returns the Unknown value (?).

Example — Determining which files differ between application versions

The MD5 value is a 128-bit unique key that is stored within a compiled procedure. Changing one character in a procedure file results in a different MD5 value. With the MD5-VALUE attribute for the RCODE-INFO system handle, you can determine which r-code files need to be replaced in your application between versions. The following example code shows the output of the MD5-VALUE attribute:

DEFINE VARIABLE charmd5 AS CHARACTER. 
RCODE-INFO:FILE-NAME = "main.r". 
charmd5 = RCODE-INFO:MD5-VALUE. 
MESSAGE "MD5 value of main.r: " charmd5. 

This code results in the following output:

MD5 value of main.r: E3AD5B5C009B8FA1C20067304161B6CC0D 

You could create a program that runs this code for two versions of the same procedure file and then compare the resulting outputs. If they are the same, you know the contents of the procedure file has not changed between the two versions.

If you did not use the GENERATE-MD5 option on the COMPILE statement to compile a procedure, Progress did not store the MD5 value in the r-code file. In this case, this attribute returns the Unknown value (?).


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095